module API::V3
  class Users < Grape::API
    include TrafficConvert
    resource :users do
      params do
        requires :account_id, type: Integer
        requires :mac, type: String, regexp: /\A([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2}\z/
      end
      post :signin do
        account = Account.find_by_id(params[:account_id])
        terminal = Terminal.where(mac: params[:mac]).first

        # check whether the account exists
        if account == nil || terminal == nil
          error_code = 1
          message = "account or terminal doesn't exist"
        else
          error_code = 0

          # get creditcard, if none, create it
          creditcard = Creditcard.where(account_id: account.id, terminal_group_id: terminal.terminal_group_id).first_or_create(account_id: account.id, terminal_group_id: terminal.terminal_group_id)

          # refresh the creditcard
          creditcard.refresh!

          # log the sign in
          account.last_seen = Time.now
          account.save
          AccountSignin.create_from_params account, terminal
        end

        # send response
        present :result, error_code == 0
        if error_code == 0
          present :creditcard_id, creditcard.id
          present :avaliable, creditcard.avaliable?
          if creditcard.avaliable?
            present :up, creditcard.limit_up
            present :down, creditcard.limit_down
          end
        else
          present :error_code, error_code
          present :message, message
        end
      end

      params do
        requires :mobile_number, type: String
        requires :password, type: String
      end
      post :login do
        account = Account.find_by_mobile_number(params[:mobile_number])
        if account.nil?
          message = "Account doesn't exist"
          error_code = 1
        elsif account.authenticate(params[:password])
          error_code = 0
        else
          error_code = 2
          message = "Password doesn't match"
        end

        present :result, error_code == 0
        if error_code == 0
          present :account_id, account.id
        else
          present :message, message
          present :error_code, error_code
        end        
      end

      params do
        requires :mac, type: String, regexp: /\A([a-fA-F0-9]{2}:){5}[a-fA-F0-9]{2}\z/
        requires :account_id, type: Integer
        optional :bind, type: Boolean, default: true
      end
      post :bind do
        error_code = 0
        account = Account.find_by_id params[:account_id]

        if account.nil?
          message = "account doesn't exist"
          error_code = 1
        else
          terminal = PersonalTerminal.where(mac: params[:mac]).first_or_create
          if params[:bind] && terminal.account_id && terminal.account_id != account.id
            message = "terminal has been binded"
            error_code = 2
          elsif !params[:bind] || terminal.account_id.nil? || terminal.account_id == account.id
            terminal.update_attributes(account_id: params[:bind] ? account.id : nil)
          end
        end

        present :result, error_code == 0
        if error_code != 0
          present :message, message
          present :error_code, error_code
        end
      end

      params do
        requires :mobile_number, type: String, regexp: /\A\d{11}\z/
        requires :verify_code, type: String, regexp: /\A\d+\z/
        optional :password, type: String
      end 
      post :signup do
        mobile_number = params[:mobile_number]

        auth_message = AuthMessage.where(mobile_number: mobile_number).first
        if !auth_message || auth_message.verify_code != params[:verify_code]
          message = "verify code doesn't match"
          error_code = 2
        elsif auth_message.activated_at < Time.now
          message = "verify code is out-of-date"
          error_code = 1
        else
          account = Account.where(mobile_number: mobile_number).first_or_create

          if params[:password].present?
            account.password = account.password_confirmation = params[:password]
          end

          account.last_seen = Time.now
          account.save
          error_code = 0
        end

        present :result, error_code == 0
        if error_code == 0
          present :account_id, account.id
        else
          present :message, message
          present :error_code, error_code
        end
      end

      params do
        requires :duration, type: Integer
        requires :traffic, type: String
      end
      post "creditcard/:creditcard_id/connection" do
        creditcard = Creditcard.find_by_id(params[:creditcard_id])
        traffic_flow = traffic_flow_from_params params[:traffic]
        if creditcard == nil
          error_code = 1
          message = "creditcard doesn't exist"
        else
          error_code = 0
          # create the connection record
          connection = Connection.new(duration: params[:duration], traffic: traffic_flow)
          connection.creditcard = creditcard
          connection.save

          # update creditcard
          creditcard.duration_used += params[:duration]
          creditcard.traffic_used += traffic_flow
          creditcard.duration_rest = [creditcard.duration_rest - params[:duration], 0].max unless creditcard.duration_total == -1
          creditcard.traffic_rest = [creditcard.traffic_rest - traffic_flow, 0].max unless creditcard.traffic_total == -1
          creditcard.save
        end

        # tell the terminal whether it's avaliable
        present :result, error_code == 0
        if error_code == 0
          present :creditcard_id, params[:creditcard_id]
          present :avaliable, creditcard.avaliable?
          present :rest_times, creditcard.rest_times
        else
          present :message, message
          present :error_code, error_code
        end
      end

      get "creditcard/:creditcard_id" do
        creditcard = Creditcard.find_by_id(params[:creditcard_id])
        if creditcard == nil
          error_code = 1
          message = "creditcard doesn't exist"
          present :result, false
          present :error_code, error_code
          present :message, message
        else
          card = { result: true }
          card[:creditcard_id] = params[:creditcard_id]
          card[:rest_times] = creditcard.rest_times
          card[:avaliable] = creditcard.avaliable?
          card[:duration] = { total: creditcard.duration_total, used: creditcard.duration_used, rest: creditcard.duration_rest }
          card[:traffic] = { total: traffics_friendly_format(creditcard.traffic_total).to_s, used: traffics_friendly_format(creditcard.traffic_used).to_s, rest: traffics_friendly_format(creditcard.traffic_rest).to_s }
          card[:limit] = { up: creditcard.limit_up, down: creditcard.limit_down }
          present card
        end
      end
    end

  end
end